package com.zp.base.admin.service.impl;

import com.zp.base.admin.vo.UserVo;
import com.zp.base.admin.common.utils.PageUtils;
import com.zp.base.admin.common.utils.Query;
import com.zp.base.admin.dao.MenuDao;
import com.zp.base.admin.entity.MenuEntity;
import com.zp.base.admin.entity.RoleMenuEntity;
import com.zp.base.admin.entity.UserRoleEntity;
import com.zp.base.admin.service.RoleMenuService;
import com.zp.base.admin.service.UserRoleService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.zp.base.admin.dao.UserDao;
import com.zp.base.admin.entity.UserEntity;
import com.zp.base.admin.service.UserService;
import org.springframework.transaction.annotation.Transactional;


/**
 * @author 张鹏
 */
@Service("userService")
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {

    @Autowired
    UserDao userDao;
    @Autowired
    UserRoleService userRoleService;
    @Autowired
    BCryptPasswordEncoder passwordEncoder;
    @Autowired
    MenuDao menuDao;
    @Autowired
    RoleMenuService roleMenuService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {

        IPage<UserEntity> page = this.page(
                new Query<UserEntity>().getPage(params),
                new QueryWrapper<UserEntity>().like("username", params.get("username"))
        );

        return new PageUtils(page);
    }

    @Override
    public UserEntity findByUsername(String username) {
        return userDao.selectOne(new QueryWrapper<UserEntity>().eq("username", username));
    }

    @Override
    public boolean addUser(UserVo addUserVo) {
        try {
            UserEntity userEntity = new UserEntity();
            //将密码加密存入数据库
            addUserVo.setPassword(passwordEncoder.encode(addUserVo.getPassword()));
            BeanUtils.copyProperties(addUserVo, userEntity);
            userDao.insert(userEntity);

            //向用户-角色关联表添加
            List<UserRoleEntity> userRoleEntities = getUserRoleEntities(addUserVo.getRoleId(), userEntity.getId());
            userRoleService.saveBatch(userRoleEntities);

            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }

    @Override
    public boolean usernameIsExists(String username, long id) {
        UserEntity byUsername = this.findByUsername(username);
        if (byUsername != null && byUsername.getId() != id) {
            return true;
        }
        return false;
    }

    @Override
    public boolean updateUser(UserVo updateUserVo) {
        try {
            //检查密码是否修改 与数据库对比
            UserEntity userEntity1 = userDao.selectById(updateUserVo.getId());
            if (userEntity1.getPassword().equals(updateUserVo.getPassword())) {
                updateUserVo.setPassword(null);
            } else {
                updateUserVo.setPassword(passwordEncoder.encode(updateUserVo.getPassword()));
            }
            UserEntity userEntity = new UserEntity();
            BeanUtils.copyProperties(updateUserVo, userEntity);
            //修改用户表
            userDao.updateById(userEntity);
            //修改用户 角色关联表
            //先删除之前的 再重新添加
            userRoleService.remove(new QueryWrapper<UserRoleEntity>().eq("user_id", userEntity.getId()));
            List<UserRoleEntity> userRoleEntities = getUserRoleEntities(updateUserVo.getRoleId(), userEntity.getId());
            userRoleService.saveBatch(userRoleEntities);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }

    @Override
    public UserVo selectByUserId(Long id) {
        //获取用户表信息
        UserEntity userEntity = userDao.selectById(id);
        //获取角色 用户关联表信息
        List<UserRoleEntity> userRoleEntities = userRoleService.list(new QueryWrapper<UserRoleEntity>().eq("user_id", userEntity.getId()));
        List<Long> collect = userRoleEntities.stream().map(userRoleEntity -> userRoleEntity.getRoleId()).collect(Collectors.toList());

        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(userEntity, userVo);
        userVo.setRoleId(collect);
        return userVo;
    }

    @Override
    public boolean deleteByUserId(Long id) {
        try {
            //先删除关联表信息  用户角色
            userRoleService.remove(new QueryWrapper<UserRoleEntity>().eq("user_id", id));
            //删除主表信息
            userDao.deleteById(id);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }

    @Override
    public List<MenuEntity> getMenusByUserId(Long id) {
        //看用户有什么可用角色（排除冻结的角色的权限）
        List<Long> roleIds = userDao.getRoleIdsByUserId(id);
        List<RoleMenuEntity> roleMenuEntities = roleMenuService.list(new QueryWrapper<RoleMenuEntity>().in("role_id", roleIds));
        List<Long> menuIds = roleMenuEntities.stream().map(roleMenuEntity -> roleMenuEntity.getMenuId()).collect(Collectors.toList());
        List<MenuEntity> menuEntities = menuDao.selectList(new QueryWrapper<MenuEntity>().in("id", menuIds));
        return menuEntities;
    }

    @Override
    public List<String> findRolesByUserId(Long id) {
        return userDao.findRolesByUserId(id);
    }

    private List<UserRoleEntity> getUserRoleEntities(List<Long> roleIds, Long id) {
        if (roleIds != null && roleIds.size() > 0) {
            List<UserRoleEntity> userRoleEntities = new ArrayList<>();
            for (Long roleId : roleIds) {
                UserRoleEntity userRoleEntity = new UserRoleEntity();
                userRoleEntity.setRoleId(roleId);
                userRoleEntity.setUserId(id);
                userRoleEntities.add(userRoleEntity);
            }
            return userRoleEntities;
        }
        return null;
    }

    /**
     * 登录认证时spring security会调用该方法  根据用户名查询出该用户，并把该用户拥有的角色和权限绑定好
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserEntity userEntity = userDao.selectOne(new QueryWrapper<UserEntity>().eq("username", username));
        List<GrantedAuthority> authorities = new ArrayList<>();
        //获取角色和权限
        if (userEntity != null) {
            List<String> roles = userDao.findRolesByUserId(userEntity.getId());
            if (roles != null && roles.size() > 0) {
                for (String role : roles) {
                    authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
                }
                List<String> strings = userDao.findPermissionsByUserId(userEntity.getId());
                if (strings != null && strings.size() > 0) {
                    //去重  用户可能有多个角色 这些角色的权限有交集
                    Set<String> permissions = new HashSet<>(strings);
                    for (String permission : permissions) {
                        authorities.add(new SimpleGrantedAuthority(permission));
                    }
                }
            }
            userEntity.setAuthorities(authorities);
        }
        return userEntity;
    }
}